import React, { createElement } from "react"
import MyImg from "../my-img"
import MyH1 from "../my-h1"

interface Components {
  [key: string]: React.FC<any>
}
const cops: Components = {
  MyImg,
  MyH1,
}

// console.log(cops["my_img"])

const img = createElement(cops["my_img"], {
  src: "https://fuyouplus.oss-cn-beijing.aliyuncs.com/blog-imgs/24.png",
})

const h1 = createElement(
  cops["MyH1"],
  null,
  createElement(
    "span",
    {
      style: {
        color: "blue",
      },
    },
    "内容"
  )
)
enum NodeType {
  Element = 1,
  Text = 3,
}

const warn = (msg: string) => {
  console.warn(`[微若蜉蝣]:${msg}`)
}

const parseProps = (element: HTMLElement): object | null => {
  if (element.attributes.length == 0) return null
  let props: {
    [key: string]: unknown
  } = {}
  for (let i = 0; i < element.attributes.length; i++) {
    let attr = element.attributes[i]
    props[attr.name] = attr.value
  }
  return props
}

const templateTransformNodes = (template: string): HTMLElement | Text | void => {
  const container: HTMLDivElement = document.createElement("div")
  container.innerHTML = template
  if (container.childNodes.length > 1) {
    warn("模板只能存在一个根节点！")
    return
  }
  const firstNode: Node = container.childNodes[0]

  if (firstNode.nodeType == NodeType.Element) {
    return firstNode as HTMLElement
  } else if (firstNode.nodeType == NodeType.Text) {
    return document.createTextNode(firstNode.nodeValue as string) as Text
  }
}

const transformNodeNameKebabCaseToPascalCase = (nodeName: string): string => {
  nodeName = nodeName.replace(/-(\w)/g, (_, $1: string) => $1.toUpperCase())
  const nodeNameArr = nodeName.split("")
  nodeNameArr[0] = nodeNameArr[0].toUpperCase()
  return nodeNameArr.join("")
}

const nodesTransformVNodes = (
  node: Node | void,
  components: Components
): React.FunctionComponentElement<{}> | void | string => {
  if (!node) {
    warn("无效的Node!")
    return
  }
  const createChildren = (children: NodeList): Array<React.FunctionComponentElement<{}>> => {
    const childrenVNodes: Array<React.FunctionComponentElement<{}> | string | null> = []
    if (children.length) {
      children.forEach((item: Node) => {
        childrenVNodes.push(
          item.nodeType == NodeType.Text
            ? item.nodeValue
            : (nodesTransformVNodes(item, components) as React.FunctionComponentElement<{}>)
        )
      })
    }
    return childrenVNodes as Array<React.FunctionComponentElement<{}>>
  }

  if (node.nodeType == NodeType.Element) {
    console.dir(node)
    const NodeName = transformNodeNameKebabCaseToPascalCase(node.localName)
    console.log(NodeName)
    return createElement(
      components[NodeName] ? components[NodeName] : node.localName,
      { ...parseProps(node as HTMLElement), key: Math.random() },
      createChildren(node.childNodes)
    ) as React.FunctionComponentElement<{}>
  } else {
    return node.nodeValue as string
  }
}

const template = `<div><my-img src="https://fuyouplus.oss-cn-beijing.aliyuncs.com/blog-imgs/24.png"></my-img></div>`
const nodes = templateTransformNodes(template)
const VNodes = nodesTransformVNodes(nodes, cops)
console.log(VNodes)

const Test: React.FC<{}> = () => {
  return VNodes
}
export default Test
